package robotemulator;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

import javax.swing.JPanel;

/**
 * Handles points on a graph as well as provides interactive viewing of the graph.
 * 
 * @author Patrick Jameson
 * @version 11.20.2010.0
 */
@SuppressWarnings("serial")
public class Graph extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener {
	private int width, height, xAxisLoc, yAxisLoc, preX, preY, mouseX, mouseY;
	private int yStart, yEnd;
	private int scale;
	private double[][] points = {};
	private boolean restrictedRange;
	private double range1, range2;
	
	public Graph(int _width, int _height) {
		width = _width;
		height = _height;
		xAxisLoc = width/2;
		yAxisLoc = height/2;
		
		scale = 12;
		restrictedRange = false;
		
		
		addMouseListener(this);
		addMouseMotionListener(this);
		addMouseWheelListener(this);
	}
	/**
	 * Draws the graph.
	 */
	public void paintComponent(Graphics g) {
		//clears graph.
		g.setColor(Color.gray);
		g.fillRect(0,0,width,height);
		
		//draws grid.
		g.setColor(new Color(230, 230, 230));//greyish
		if (restrictedRange) {
			yStart = (int)(yAxisLoc-(scale*range1));
			yEnd = (int)(yAxisLoc+(scale*range2));
		} else {
			yStart = yAxisLoc%scale;//to line up the x axis with the background grid.
			yEnd = height;
		}
		
		//clears graphing area.
		g.setColor(Color.white);
		g.fillRect(0, yStart, width, yEnd-yStart);
		
		g.setColor(new Color(230, 230, 230));//greyish
		for (int x = 0;x <= width;x+=scale)
			g.drawLine(x+xAxisLoc%scale, yStart, x+xAxisLoc%scale, yEnd);
		for (int y = yStart;y <= yEnd;y+=scale)
			g.drawLine(0, y, width, y);
		
		//draws x and y axis.
		g.setColor(Color.black);
		//g.drawLine(xAxisLoc, 0, xAxisLoc, height);//y axis.
		g.drawLine(0, yAxisLoc, width, yAxisLoc);//x axis.
		
		//draw points
		g.setColor(Color.red);
		for (int i = 0;i < points.length;i++) {
			int x = (int)(xAxisLoc+(points[i][0]*scale));
			int y = (int)(yAxisLoc-(points[i][1]*scale));
			//g.fillOval(x-scale/6, y-scale/6, scale/3, scale/3);//draws a dot at each point.
			if (i < points.length-1)
				g.drawLine(x, y, (int)(xAxisLoc+(points[i+1][0]*scale)), (int)(yAxisLoc-(points[i+1][1]*scale)));
		}
		
		//draws box next to mouse showing points.
		/*g.setColor(Color.black);
		double x = (xAxisLoc-mouseX)/(double)scale;
		double y = (yAxisLoc-mouseY)/(double)scale;
		g.drawString("("+round(x, 2) + ", ", mouseX, mouseY);
		g.drawString(round(y, 2)+")", mouseX+60, mouseY);*/
	}
	
	public double round(double preNum, int decPlaces) {
    	return (double)Math.round((preNum*Math.pow(10, decPlaces)))/Math.pow(10, decPlaces);
    }
	
	/**
	 * Sets the points to be graphed.
	 * 
	 * @param _points points to be graphed in the format of _points[point number][0 for x and 1 for y]
	 */
	public void setPoints(double[][] _points) {
		points = _points;
		repaint();
	}
	
	/**
	 * Gets the starting point for use in mouseDragged.
	 */
	public void mousePressed(MouseEvent e) {
		preX = e.getX();
		preY = e.getY();
	}
	
	/**
	 * Moves graph with the dragging of the mouse.
	 */
	public void mouseDragged(MouseEvent e) {
		moveGraph(e.getX() - preX, e.getY() - preY);
		preX = e.getX();
		preY = e.getY();
		/*mouseX = preX;
		mouseY = preY;*/
	}
	
	/**
	 * moves the graph by (mX, mY)
	 * @param mX move the x axis mX pixels
	 * @param mY move the y axis mY pixels
	 */
	public void moveGraph(int mX, int mY) {
		xAxisLoc += mX;
		yAxisLoc += mY;
		repaint();
	}
	
	/**
	 * Sets the view of the graph at width/2 based on the value of pX.
	 * @param pX value that will be shown in the position of width/2
	 */
	public void setXAxisPosition(double pX) {
		xAxisLoc = (int)(pX*scale)*-1+width/2;
		repaint();
	}
	
	/**
	 * Sets the view of the graph at width/2 based on the value of pY.
	 * @param pY value that will be shown in the position of width/2
	 */
	public void setYAxisPosition(double pY) {
		yAxisLoc = (int)(pY*scale)*-1+width/2;
		repaint();
	}
	
	/**
	 * TODO: Restricts the graph to the range provided.
	 * @param _range1
	 * @param _range2
	 */
	public void setRange(double _range1, double _range2) {
		restrictedRange = true;
		range1 = _range1;
		range2 = _range1;
	}
	
	/**
	 * Zooms the graph in and out when user rolls the mouse wheel relative to the position of the mouse. 
	 */
	public void mouseWheelMoved(MouseWheelEvent e) {
		double preX = (xAxisLoc-e.getX())/(double)scale;
		double preY = (yAxisLoc-e.getY())/(double)scale;
		scale -= e.getWheelRotation()*3;
		if (scale < 3)
			scale = 3;
		else if (scale >= 60)
			scale = 60;
		
		xAxisLoc = (int)((preX*scale)+e.getX());
		yAxisLoc = (int)((preY*scale)+e.getY());
		repaint();
	}
	
	/**
	 * Sets the height and width of the graph.
	 * @param _width Desired width of graph.
	 * @param _height Desired height of graph.
	 */
	public void setGraphSize(int _width, int _height) {
		width = _width;
		height = _height;
	}
	
	/**
	 * @returns the current scale of the graph(zoom level)
	 */
	public int getScale() {
		return scale;
	}
	
	public void mouseMoved(MouseEvent e) {
		/*mouseX = e.getX();
		mouseY = e.getY();
		repaint();*/
	}
	
	//extra stuffs
	public void mouseReleased(MouseEvent e) {}
	public void mouseClicked(MouseEvent e) {}
	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
}
